package com.abc.server;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.serialization.ClassResolver;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;

import java.io.File;
import java.net.URL;
import java.util.*;

public class RpcServer {
    //服务注册表
    private Map<String, Object> registryMap = new HashMap<>();

    private List<String> classCache = new ArrayList<>();

    //线程安全的list ,但是当前服务是启动的时候自动加载，不会有多个线层同时操作
//    private List<String> classCache = Collections.singletonList(new ArrayList<>());

    public void publish(String bassPackage) throws Exception {
        //将指定包下面的提供者类名写入到classCache 中进行缓存
        getProviderClass(bassPackage);

        //将提供者名与实例的对应关系写入到注册表中
        doRegister();
    }

    private void getProviderClass(String bassPackage) {
        //加载指定包的url
        URL resource = this.getClass().getClassLoader()
                //com.abc.webapp => com/abc/webapp
                .getResource(bassPackage.replaceAll("\\.", "/"));
        //如果没有指定的资源则直接结束
        if (resource == null) {
            return;
        }

        File dir = new File(resource.getFile());
        //遍历指定包及其子孙包中所有的文件，查找 .class 文件
        for (File file : dir.listFiles()) {
            if (file.isDirectory()) {
                //获取当前目录下文件 递归
                getProviderClass(bassPackage + "." + file.getName());
            } else if (file.getName().endsWith(".class")) {
                //去掉.class 扩展名 获取到简单名称
                String fileName = file.getName().replace(".class", "");
                classCache.add(bassPackage + "." + fileName);
            }
        }
    }

    private void doRegister() throws Exception {
        //没有任何实现类则直接结束
        if (classCache.size() == 0) {
            return;
        }

        for (String className : classCache) {
            Class<?> clazz = Class.forName(className);
            //将业务接口名作为key ，接口实现类作为value 写入到注册表
            Class<?>[] interfaces = clazz.getInterfaces();
            if (interfaces.length ==0 ){
                continue;
            }
            registryMap.put(interfaces[0].getName(), clazz.newInstance());
        }
    }

    //启动器
    public void start() throws Exception {
        NioEventLoopGroup parentGroup = new NioEventLoopGroup();
        NioEventLoopGroup childGroup = new NioEventLoopGroup();
        try{
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(parentGroup, childGroup)
                    //制定存放已经连接上但是还来不及处理的请求队列长度
                    .option(ChannelOption.SO_BACKLOG, 1024)
                    //为了保证长连接不被清除
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline pipeline = ch.pipeline();
                            pipeline.addLast(new ObjectEncoder());
                            pipeline.addLast(new ObjectDecoder(Integer.MAX_VALUE,
                                    ClassResolvers.cacheDisabled(null)));
                            pipeline.addLast(new RpcServerHandler(registryMap));
                        }
                    });
            ChannelFuture future = bootstrap.bind(8888).sync();
            System.out.println("rpc 启动");
            future.channel().closeFuture().sync();
        }finally {
            parentGroup.shutdownGracefully();
            childGroup.shutdownGracefully();
        }
    }


}
